﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2010-06-11
//
// Update Date : 2010-08-15
//     增加2D功能相关函数
//     1. 2D 的 Quad 索引规则(D3DPT_TRIANGLELIST方式):
//        0 .__. 1
//          | /|
//        2.|/_|.3  D3D逆时针0,1,2,2,1,3
//
// Update Date : 2011-05-04
//    增加3D功能相关函数
//    1.我们的坐标轴（单位：米）
//       +z |
//          |
//          |_______ +x
//          /
//         /
//        / +y
//    2.我们的旋转关系
//        +z |→
//           |
//           |_______ +x
//           /      ↓
//          /
//       ↑/ +y
//
//    3.矩阵转换顺序: 缩放 * 旋转 * 平移
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#pragma pack(push,1)


//----------------------------------------------------------------
// 3D 地形混合图
//----------------------------------------------------------------
struct FTERRAIN_BLEND_TEXTURE
{
    FIDTEXTURE tex[eCD_CHUNK_BLEND_TEX];  // 颜色贴图，法线贴图，备用贴图

    FTERRAIN_BLEND_TEXTURE()
    {
        clear();
    }
    void clear()
    {
        for (size_t i = 0; i < eCD_CHUNK_BLEND_TEX; ++i)
            tex[i] = eCD_ErrorTex;
    }
};

//----------------------------------------------------------------
// 3D vegetation
//----------------------------------------------------------------
struct FVEGETATION_PROP
{
    FDECLARE_STRUCT(FVEGETATION_PROP)

    // 宽度和高度可以优化到一个符点数上面
    // 整个结构可以压到4个符点数

    // V4
    float width;    // 面片宽
    float height;   // 面片高
    float rot_z;    // z轴旋转 （[-pi,+pi]）
    float intensity;// 面片强度（[0,1]）
    // V4
    float x, y, z;  // 坐标
    float blend;    // 亮度

    FVEGETATION_PROP()
        :rot_z(0)
        ,intensity(0.85f)
        ,blend(1)
    {}
};

#pragma pack(pop)


class IFRender : public IFService
{
    friend class FEngine;

protected:
    explicit IFRender()
        :IFService(0)
    {}


    //----------------------------------------------------------------
    // 公共处理函数
    //----------------------------------------------------------------
public:
    // 提交缓冲区的数据，以方便应用程序下一步工作
    // .flags 提交哪些分类数据（eRCF_All为全部提交）
    // 注意：每帧结束的时候会自动提交全部，除非是你知道必须提前提交一些数据到缓冲区才调用此接口
    virtual void Commit(DWORD flags = eRCF_All) = 0;
    // 清理缓冲区的数据
    // .flags 清理的对象类型
    virtual void Clear(DWORD flags = eRCF_All) = 0;


    //----------------------------------------------------------------
    // 2D功能函数
    //----------------------------------------------------------------
public:
    // 画线
    // .start 顶点起点数组
    // .end 顶点终点数组
    // .color 线段的颜色
    virtual void DrawLine2D(const FVECTOR2* start, const FVECTOR2* end, DWORD color) = 0;
    // 画2D区域
    // .dst 屏幕位置（X坐标,Y坐标,W宽，H高，不同于WINDOWS的RECT）
    // .color 颜色
    // .isfill 是否填充区域内部，否则为只画边框
    virtual void DrawRect(FRect* dst, DWORD color, bool isfill) = 0;
    // 画圆
    // .center 圆的中心点
    // .radius 圆的半径
    // .segment 360度将分成多少片（范围：[3-180]闭区间）
    // .color 颜色
    // .isfill 是否是填充圆，否则是画圆边线
    virtual void DrawCircle2D(const FVECTOR2* center, float radius, int segment, DWORD color, bool isfill) = 0;
    // 绘制精灵
    // .id 贴图ID
    // .dx.dy,dw,dh 屏幕区域
    // .sx,sy,sw,sh 贴图源区域
    // .color 颜色
    // .flags 渲染标记
    virtual void DrawSprite(FIDTEXTURE id, float dx, float dy, float dw, float dh,
        float sx, float sy, float sw, float sh, DWORD color = 0xFFFFFFFF, DWORD flags = eRF_Default2D) = 0;
    // 绘制精灵
    // .id 贴图ID
    // .pvtx 精灵顶点缓冲区，顶点排列方式见本文件顶部
    // .quad_count 精灵数量，一个精灵4个顶点，6个索引（索引方式和排列顺序见本文件顶部）
    // .flags 渲染标记
    virtual void DrawSprite(FIDTEXTURE id, FVERTEX2D *pvtx, WORD quad_count, DWORD flags = eRF_Default2D) = 0;
    // 绘制精灵（可以是非矩形）
    // .id 贴图ID
    // .p0,p1,p2,p3 屏幕中的坐标点（索引方式和排列顺序见本文件顶部）
    // .sx,sy,sw,sh 贴图源区域
    // .color 颜色
    // .flags 渲染标记
    virtual void DrawSprite4V(FIDTEXTURE id, FVECTOR2* p0, FVECTOR2* p1, FVECTOR2* p2, FVECTOR2* p3,
        float sx, float sy, float sw, float sh, DWORD color = 0xFFFFFFFF, DWORD flags = eRF_Default2D) = 0;
    // 绘制精灵
    // .id 贴图ID
    // .dx.dy 屏幕位置
    // .sx,sy,sw,sh 贴图源区域
    // .cx,cy 精灵中心位置
    // .rot 旋转度
    // .hscale 水平缩放
    // .vscale 垂直缩放，如果为0则使用hscale填充
    // .color 颜色
    // .reversal 翻转模式(EF_REVERSAL_MODE)
    // .flags 渲染标记(EF_RENDER_FLAGS)
    virtual void DrawSpriteEx(FIDTEXTURE id, float dx, float dy, float sx, float sy, float sw, float sh, 
        float cx, float cy, float rot, float hscale = 1.0f, float vscale = 0.0f, 
        BYTE reversal = eRM_None, DWORD color = 0xFFFFFFFF, DWORD flags = eRF_Default2D) = 0;
    // 渲染数字
    // .x,y 屏幕位置
    // .pvl 要渲染的数字数据地址，通过flags标记来设定此数据指针指向的是什么类型
    // .vspr 精灵数组 "IFSpriteObject* vspr[eNT_MAX]"，排列顺序详见 EF_NUMBER_TYPE
    // .rot 旋转角度
    // .algin 对齐模式 详见 EF_NUMBER_RENDER
    // .flags 渲染模式，详见 EF_NUMBER_MODE
    virtual void DrawNumber2D(float x, float y, void* pvl, IFSpriteObject** vspr, float rot = 0,
        EF_NUMBER_RENDER algin = eNR_LEFT, DWORD flags = eNF_INT) = 0;
    // 设置截剪区域(缓冲区级截剪)
    // .prect 屏幕目标区域，填0表示恢复截剪
    // 注意：此函数仅2D渲染下有效，3D下请使用IFGraph的SetScissorRect函数。
    virtual void Clip2D(const FRect* prect) = 0;
    // 设置2D环境数据
    // .gray 是否灰度显示
    // .brightness 高亮参数
    // .contrast 对比度参数
    virtual void SetEnv2D(bool gray = false, float brightness = FE_DEF_BRIGHTNESS, float contrast = FE_DEF_CONTRAST) = 0;
    // 设置2D颜色补尝
    // .t 补偿模式
    // .c 补偿颜色（只处理RGB数据，Alpha不处理）
    virtual void SetColorAppend2D(EF_COLOR_APPEND_FLAGS t = eCAF_None, DWORD c = 0) = 0;

    //----------------------------------------------------------------
    // 3D功能函数
    //----------------------------------------------------------------
public:
    // 绘制一条线段
    // .start 线段起点
    // .end 线段终点
    // .color 线段颜色
    // .endcolor 线段的结束点颜色，如果此值为0则整个线段用同一颜色color
    virtual void DrawLine3D(const FVECTOR3* start, const FVECTOR3* end, DWORD color, DWORD endcolor = 0) = 0;
    // 绘制一堆线段
    // .vline 线段缓存的首地址
    // .lcount 线段的数量，不是线段缓冲点的数量（1线段2个点）
    virtual void DrawLine3D(FVERTEX3D_LINE* vline, size_t lcount) = 0; 
    // 绘制包围盒
    // .bbox 包围盒数据
    // .color 线条颜色
    virtual void DrawAABB(FAABB& box, DWORD color = 0xFFC0C0C0) = 0;
    // 绘制视锥
    // .frustum 视锥体对象
    // .color 线条颜色
    // .draw_number 是否显示各顶点的编号
    virtual void DrawFrustum(FFRUSTUM* frustum, DWORD color = 0xFFC0C0C0, bool draw_number = false) = 0;
    // 绘制广告牌（如3D的雪花，粒子，广告牌都可以用此函数）
    // .id 贴图ID
    // .flags 该贴图的渲染标记，最好使用 eRF_3DEffect
    // .pos 广告牌的3D位置
    // .width,height 广牌的宽和高，不是图片的宽和高
    // .alpha 透明度
    // .color 顶点颜色
    // .scale 粒子缩放度
    // .mod_scale 模型或者世界缩放
    // .rot 旋转度
    // .dir 运动方向*长度(如果填了则粒子不按正方形显示)
    virtual void DrawBillboard(FIDTEXTURE id, DWORD flags, FVECTOR3* pos, float width, float height, 
        float alpha, DWORD color, float scale, float mod_scale, float rot, FVECTOR3* dir = 0) = 0;
    virtual void DrawBillboard(FIDTEXTURE id, DWORD flags, int cellidx, int wcount, int hcount, FVECTOR3* pos, 
        float width, float height, float alpha, DWORD color, float scale, float mod_scale, float rot, FVECTOR3* dir = 0) = 0;
    // 绘制刀光
    virtual void DrawRibbon(FIDTEXTURE id, DWORD flags, FVECTOR3* vpos, size_t pos_count, float alpha, DWORD color) = 0;
    // 渲染一个动画对象
    virtual void DrawAnimation(IFAnimation* ani, float alpha = 1.0f){ if (ani) ani->Render(alpha); }
    // 绘制某个模型文件的子集
    // .anim 模型动画
    // .subset_idx 该模型中子集索引
    // .alpha 透度度
    // .draw_normal 是否显示法线
    virtual void DrawSubset(IFAnimation* anim, size_t subset_idx, float alpha, bool draw_normal = false) = 0;
    // 渲染某个地形中单个局部中的单个地块
    // .ex,ey 该地块的起始坐标
    // .height_tex 高度
    // .alpha_tex 4层混合图混度度
    // .blend0->blend4 4层混合图的材质
    // .frame_mode 线框模式渲染
    virtual void DrawTerrain(float ex, float ey, FIDTEXTURE height_tex, FIDTEXTURE alpha_tex,
        FTERRAIN_BLEND_TEXTURE* blend[eCD_CHUNK_ALPHA_LAYER], bool frame_mode = false) = 0;
    // 渲染植被
    // .tex 植被使用的贴图
    // .count 植被数量
    // .vegetation_lst 植被参数列表
    virtual void DrawVegetation(FIDTEXTURE noise, FIDTEXTURE tex, size_t count, FVEGETATION_PROP* vegetation_lst) = 0;
    // 画天空盒（注意，每次提交Commit操作只会渲染最后一次调用DrawSkybox设置的天空盒贴图）
    // .cube_sky 天空盒的立方贴图，如果cube_sky为eCD_ErrorTex由表示清天空盒，在Commit的时候就看不到天空了
    virtual void DrawSkybox(FIDTEXTURE cube_sky) = 0;
    // 水面渲染
    virtual void DrawWater(float ex, float ey, float height, DWORD color) = 0;
};